#include "general.h"
#include "liquid.h"
#include <zlib.h>

#include <buola/gui/cimagematrix.h>
#include <buola/image/algorithm/color.h>

namespace buola { namespace gui {

void CColorMatrixPool::Init(int pType,img::CImage_rgba8 &&pI1,img::CImage_rgba8 &&pI2,img::CImage_rgba8 &&pI3)
{
    mType=pType;
    mI1=std::move(pI1);
    mI2=std::move(pI2);
    mI3=std::move(pI3);
}

void CColorMatrixPool::Init(img::CImage_rgba8 &&pImage,const CRect_d &pRect)
{
    mType=COLOR_MATRIX_9;
    mI1=std::move(pImage);
    mRect=pRect;
}

CImageMatrix *CColorMatrixPool::Get(const img::CColor &pColor)
{
    unsigned int lRGB=pColor.RGBA();

    for(int i=0;i<mAll.size();i++)
    {
        if(mAll[i]->mRGB==lRGB)
            return mAll[i]->mMatrix;
    }

    CImageMatrix *lReturn=nullptr;

    if(mType==COLOR_MATRIX_9)
    {
        img::CImage_rgba8 lImage=clone(mI1);
        img::saturate(lImage,pColor);

        lReturn=new CImageMatrix;
        lReturn->Create(clone(lImage),mRect);
    }
    else if(mType==COLOR_MATRIX_3H)
    {
        img::CImage_rgba8 lI1=clone(mI1);
        img::CImage_rgba8 lI2=clone(mI2);
        img::CImage_rgba8 lI3=clone(mI3);
        img::saturate(lI1,pColor);
        img::saturate(lI2,pColor);
        img::saturate(lI3,pColor);

        lReturn=new CImageMatrix;
        lReturn->Create3H(lI1,lI2,lI3);
    }
    else if(mType==COLOR_MATRIX_3V)
    {
        img::CImage_rgba8 lI1=clone(mI1);
        img::CImage_rgba8 lI2=clone(mI2);
        img::CImage_rgba8 lI3=clone(mI3);
        img::saturate(lI1,pColor);
        img::saturate(lI2,pColor);
        img::saturate(lI3,pColor);
        
        lReturn=new CImageMatrix;
        lReturn->Create3V(lI1,lI2,lI3);
    }

    if(!lReturn) throw XInternal(I18N("Can't create image matrix"));

    CColorMatrix *lMatrix=new CColorMatrix;
    lMatrix->mRGB=lRGB;
    lMatrix->mMatrix=lReturn;
    mAll.push_back(lMatrix);

    return lReturn;
}

void CColorImagePool::Init(const img::CPicture &pImage)
{
    mImage=pImage;
}

img::CPicture CColorImagePool::Get(const img::CColor &pColor)
{
    unsigned int lRGB=pColor.RGBA();

    for(int i=0;i<mAll.size();i++)
    {
        if(mAll[i]->mRGB==lRGB)
            return mAll[i]->mImage;
    }

    ///\todo
    return mImage;
//    PImage lReturn=new CImage;
//    lReturn->Create(mImage);
//    lReturn->Saturate(pColor);
//
//    CColorImage *lImage=new CColorImage;
//    lImage->mRGB=lRGB;
//    lImage->mImage=lReturn;
//    mAll.push_back(lImage);
//
//    return lReturn;
}

img::CPicture CCairoHelper::LoadImage(int i)
{
    SCairoImage &lI=sCairoImages[i];
    uLongf lRealLen=(((uint32_t)lI.mData[0])<<24)+(((uint32_t)lI.mData[1])<<16)+
                    (((uint32_t)lI.mData[2])<<8)+((uint32_t)lI.mData[3]);

    unsigned char *lBuffer=(unsigned char*)alloc_mem(lRealLen);

    uncompress(lBuffer,&lRealLen,lI.mData+4,lI.mLength-4);

    return clone(img::view_rgba8(lBuffer,CSize_i(lI.w,lI.h)));
}

img::CPicture CCairoHelper::LoadImage(const std::wstring &pName)
{
    for(int i=0;sCairoImages[i].mData;i++)
    {
        if(pName==sCairoImages[i].mName)
            return LoadImage(i);
    }

    throw XNotFound(I18N("Can't find liquid image"));
}

img::CImage_rgba8 CCairoHelper::LoadImage2(int i)
{
    SCairoImage &lI=sCairoImages[i];
    uLongf lRealLen=(((uint32_t)lI.mData[0])<<24)+(((uint32_t)lI.mData[1])<<16)+
                    (((uint32_t)lI.mData[2])<<8)+((uint32_t)lI.mData[3]);

    unsigned char *lBuffer=(unsigned char*)alloc_mem(lRealLen);

    uncompress(lBuffer,&lRealLen,lI.mData+4,lI.mLength-4);

    return clone(img::view_rgba8(lBuffer,CSize_i(lI.w,lI.h)));
}

img::CImage_rgba8 CCairoHelper::LoadImage2(const std::wstring &pName)
{
    for(int i=0;sCairoImages[i].mData;i++)
    {
        if(pName==sCairoImages[i].mName)
            return LoadImage2(i);
    }

    throw XNotFound(I18N("Can't find liquid image"));
}


CImageMatrix *CCairoHelper::LoadMatrix(const std::wstring &pName)
{
    for(int i=0;sCairoMatrices[i].mImage>=0;i++)
    {
        SCairoMatrix &lM=sCairoMatrices[i];
        if(pName==sCairoImages[lM.mImage].mName)
        {
            img::CImage_rgba8 lImage=LoadImage2(lM.mImage);
            CImageMatrix *lMatrix=new CImageMatrix;
            lMatrix->Create(std::move(lImage),CRect_d(CPoint_d(lM.x,lM.y),CSize_d(lM.w,lM.h)));
            return lMatrix;
        }
    }

    throw XNotFound(I18N("Can't find liquid matrix"));
}

void CCairoHelper::InitMatrixPool(const std::wstring &pName,
                    CColorMatrixPool &pPool,bool /*pInvert*/,bool /*pRotate*/)
{
    for(int i=0;sCairoMatrices[i].mImage>=0;i++)
    {
        SCairoMatrix &lM=sCairoMatrices[i];
        if(pName==sCairoImages[lM.mImage].mName)
        {
            img::CImage_rgba8 lImage=LoadImage2(lM.mImage);
            ///\todo
//            if(pInvert)
//            {
//                lImage->FlipHorz();
//                lImage->FlipVert();
//            }
//            if(pRotate)
//            {
//                lImage->Rotate90();
//                pPool.Init(lImage,CRect_d(CPoint_d(lM.y,lM.x),CSize_d(lM.h,lM.w)));
//            }
//            else
                pPool.Init(std::move(lImage),CRect_d(CPoint_d(lM.x,lM.y),CSize_d(lM.w,lM.h)));
            break;
        }
    }
}

/*namespace gui*/ } /*namespace buola*/ }
